package it.aekidna.cleverplatypus.dataservice
{
	import as3reflect.ClassUtils;
	import as3reflect.Field;
	import as3reflect.Type;
	
	import com.adobe.utils.ArrayUtil;
	
	[RemoteClass('ValueObjectPropertiesMask')]
	/**
	 * This class can be used to describe which DTOs' properties
	 * are meaningful for server side read/update operations.
	 * A mask can be created<br>
	 * <ul>
	 * <li>to tell the server what properties to populate on a large object read from a database</li>
	 * <li>to tell the server which properties of an object coming from the server should be written to the database</li><br>
	 * </ul>
	 * 
	 * @see it.aekidna.cleverplatypus.dataservice.ValueObjectPropertiesMaskProperty ValueObjectPropertiesMaskProperty
	 */
	public class ValueObjectPropertiesMask
	{
		public static const INCLUDE : String = "INCLUDE";
		public static const EXCLUDE : String = "EXCLUDE";

		/**
		 * value can be "INCLUDE" or "EXCLUDE".<br> 
		 * INCLUDE means that only the properties listed in properties are included.<br>
		 * EXCLUDE means that all the object (the mask referes to)'s properties are include but the ones listed in properties.  
		 */ 
		public var policy : String = INCLUDE;
		
		[ArrayElementType('String')]
		/**
		 * contains a list of String property names.<br>
		 * The meaning of this list depends on the <code>policy</code> property.
		 */
		public var properties : Array = [];

		/**
		 * contains a dictionary of ( property-name : String ) --> ( mask-info : ValueObjectPropertiesMaskProperty )
		 * pairs that describe masking for non basic types (the ones supported by AMF: String, uint, int, date, Number, Boolean).
		 * 
		 * @see it.aekidna.cleverplatypus.dataservice.ValueObjectPropertiesMaskProperty ValueObjectPropertiesMaskProperty
  		 */
		public var objects : Object = {};

		/**
		 * sets the inName property as included according to the policy
		 */		
		public function includeProperty( inName : String ) : void
		{
			if( policy == INCLUDE ) 
			{
				if( !ArrayUtil.arrayContainsValue( properties, inName ) )
				{
					properties.push( inName );	
				}
			}
			else
			{
				ArrayUtil.removeValueFromArray( properties, inName );
			}
		}
				
		/**
		 * sets the inName property as included according to the policy
		 */		
		public function excludeProperty( inName : String ) : void
		{
			if( policy == EXCLUDE ) 
			{
				if( !ArrayUtil.arrayContainsValue( properties, inName ) )
				{
					properties.push( inName );	
				}
			}
			else
			{
				ArrayUtil.removeValueFromArray( properties, inName );
			}
		}
		
		/**
		 * sets all the <code>inObject</code>'s properties as included
		 */		
		public function includeAll( inObject : Object ) : void
		{
			var clazz : Class = inObject is Class ?
				inObject as Class :
				ClassUtils.forInstance( inObject );
			var type : Type = Type.forClass( clazz );
			properties = [];
			for each( var field : Field in type.fields )
			{
				properties.push( field.name );
			}
		}
				
	}
}